%option noyywrap
%option yyclass="ConfFile"

%{
	#include "conffile.h"
	#include <fstream>
	#include <cstring>
	#include <stdlib.h>
%}

LET	[a-zA-Z]
PAL	[a-zA-Z_"-""."0-9]
NUM	[0-9]
SEP	[ \t]
IGN	[.\n ]
SIG	[+-]
EXP	[eE]


%x STORE_VALUE
%x STORE_LIST

%%

<INITIAL>"["{LET}{PAL}*"]" {
	  std::string tmp;
          tmp = YYText();
	  tmp[tmp.size()-1] = '\0';
	  current_node =  &(tmp.c_str()[1]);
}

<INITIAL>{LET}{PAL}*{SEP}*= {	
			std::string tmp;
			tmp = YYText();
			// Recortamos el token por el primer espacio o tab
			for (int i = 0; i < strlen(tmp.c_str()); i++){
				if (tmp[i] == ' ' || tmp[i] == '\t'){
					tmp[i] = '\0';
					current_token = tmp.c_str();
					continue;
				}
			}
		        BEGIN(STORE_VALUE);
			}

<STORE_VALUE>{SIG}?{NUM}{NUM}* {
/*                current_value = YYText();*/
/*                setInt(current_node,current_token,atoi(current_value.c_str()));*/
                current_data.t.type = T_INT;
                current_data.t_int.val = atoi(YYText());
                setDataNode(current_node,current_token,current_data);
		BEGIN(INITIAL);
}


<STORE_VALUE>{SIG}?{NUM}+"."{NUM}+ {
/*                current_value = YYText();*/
/*                setVal(current_node,current_token,atof(current_value.c_str()));*/
                current_data.t.type = T_FLOAT;
                current_data.t_float.val = atof(YYText());
		 setDataNode(current_node,current_token,current_data);
                BEGIN(INITIAL);
}

<STORE_VALUE>"\"".*"\"" { 
/*                    const char *foo = YYText();*/
/*                string tmp(&foo[1]);*/
/*                tmp[tmp.length()-1]='\0';*/

/*                setVal(current_node,current_token,tmp);*/

                current_data.t.type = T_STRING;
                current_data.t_string.val = strdup(YYText());
                current_data.t_string.size = strlen( current_data.t_string.val);
 setDataNode(current_node,current_token,current_data);

		BEGIN(INITIAL);
}


<STORE_VALUE>true {
        current_data.t.type = T_BOOLEAN;
        current_data.t_bool.val = true;
	setDataNode(current_node,current_token,current_data);
        BEGIN(INITIAL);
}

<STORE_VALUE>false {
    current_data.t.type = T_BOOLEAN;
    current_data.t_bool.val = false;
    setDataNode(current_node,current_token,current_data);
    BEGIN(INITIAL);
}

<STORE_VALUE>\{ {
        current_list.clear();
	BEGIN(STORE_LIST);
	}

<STORE_LIST>{SIG}?{NUM}+ {
                DataNode tmp;
                tmp.t.type = T_INT;
                tmp.t_int.val = atoi(YYText());
		current_list.push_back(tmp);
}

<STORE_LIST>{SIG}?{NUM}+"."{NUM}+ {
                current_data.t.type = T_FLOAT;
                current_data.t_float.val = atof(YYText());
	        current_list.push_back(current_data);	
}

<STORE_LIST>\} {
                DataNode tmp;
                tmp.t.type = T_LIST;
                tmp.t_list.size = current_list.size();
                tmp.t_list.val = (DataNode *) malloc(sizeof(DataNode)*tmp.t_list.size);
                
                for(int i = 0; i < current_list.size(); i++)
                    tmp.t_list.val[i] = current_list[i];

                setDataNode(current_node,current_token,tmp);
		BEGIN(INITIAL);
}


<INITIAL,STORE_VALUE,STORE_LIST>{IGN}	//Nos tragamos los caracteres que nos sobran

%%

ConfFile::ConfFile()
{}

ConfFile::ConfFile(string fname)
{
    current_node = "DEFAULT";	
    load(fname);
}

ConfFile::~ConfFile()
{}

void
ConfFile::load(string fname)
{
	ifstream conffile;
	conffile.open(fname.c_str());
	yyFlexLexer::switch_streams(&conffile,&cerr);
	yylex();
}

void
ConfFile::write(string fname)
{
    FILE *filedes;
    map<string,string>::const_iterator i;

    filedes = fopen(fname.c_str(),"w");
    if(filedes == NULL)
    {
        perror("Ooops, no pude abrir el archivo");
        exit(EXIT_FAILURE);
    }

    fclose(filedes);
}

bool
ConfFile::exists(string node,string key)
{
    if (nodes.find(node) != nodes.end())
       if(nodes[node].find(key) != (nodes[node].end()))
		       return true;
    return false;
}

DataNode
ConfFile::getDataNode(string node, string key)
{
    if(exists(node,key))
        return nodes[node][key];
    else {
        DataNode tmp;
        tmp.t.type = T_NULL;
        return tmp;
    }
}

void
ConfFile::setDataNode(string node, string key, DataNode data)
{
    nodes[node][key] = data;
}

int
ConfFile::getInt(string node, string key)
{
    DataNode n = getDataNode(node,key);

    switch(n.t.type){
        case T_INT:
            return n.t_int.val;
            break;
        default:
            return INT_MAX;
            break;
    }
}

float
ConfFile::getFloat(string node, string key)
{
    DataNode n = getDataNode(node,key);

    switch(n.t.type){
        case T_FLOAT:
            return n.t_float.val;
            break;
        default:
            return 0.0;
            break;
    }
}

vector<string>
ConfFile::getNodes()
{
        vector<string> ret;
        map<string,Node>::iterator i = nodes.begin();

        do{
                ret.push_back((*i).first);
                i++;
        } while ( i != nodes.end() );

        return ret;
}

vector<string>
ConfFile::getKeys(string node)
{
        vector<string> ret;
        map<string,Node>::iterator i = nodes.find(node);


        if ( i == nodes.end() )
                return ret;

        Node::iterator j= i->second.begin();

        do{
                ret.push_back((*j).first);
                j++;
        } while ( j != i->second.end() );

        return ret;
}


vector<int>
ConfFile::getIntList(string node,string key)
{
    vector<int> ret;
    ret.clear();
    DataNode n = getDataNode(node,key);

    if( n.t.type == T_LIST ){
            ret.resize(n.t_list.size);
            for(int i = 0; i < n.t_list.size; i++)
                ret[i] = n.t_list.val[i].t_int.val;
    }
                
    return ret;
}

vector<float>
ConfFile::getFloatList(string node,string key)
{
    vector<float> ret;
    ret.clear();
    DataNode n = getDataNode(node,key);

    if( n.t.type == T_LIST ){
            ret.resize(n.t_list.size);
            for(int i = 0; i < n.t_list.size; i++)
                ret[i] = n.t_list.val[i].t_float.val;
    }
                
    return ret;
}

string 
ConfFile::getString(string node, string key)
{
    string ret;
    
    DataNode n = getDataNode(node,key);

    if ( n.t.type == T_STRING ){
        ret.resize(n.t_string.size);
        ret = n.t_string.val;
    } else
        ret = "NULL";

    return ret;
}

bool
ConfFile::getBool(string node, string key)
{
    DataNode n = getDataNode(node,key);

    if ( n.t.type == T_BOOLEAN ){
        return  n.t_bool.val;
    } else
        return false;
}




